﻿/// <reference path='../jquery-1.4.1.js' />

/*
 * version 1.3.0
 * desc:
 * 1、设置元素validator属性
 *   如<input type="text" validator="required float"/>
 * 2、调用validate进行验证
 *   如：$("input:text").validate() 则对指定的元素进行有效验证
 * 3、验证不通过是将给元素添加error的class，您需要定义error的样式。
 */
(function ($) {
    //验证配置信息
    $.validation = {
        // 验证规则
        rules: {
            "required": {
                method: "required"
            },
            "int": {
                method: "regex",
                pattern: /^(-)?\d+$/g
            },
            "+int": {
                method: "regex",
                pattern: /^\d+$/g
            },
            "float": {
                method: "regex",
                pattern: /^(-)?[0-9]+([.][0-9]{1,})?$/g
            },
            "+float": {
                method: "regex",
                pattern: /^[0-9]+([.][0-9]{1,})?$/g
            },
            "money": {
                method: "regex",
                toOriginal: function (val) { return val.replace(/[,]/g, ""); }, //去掉格式化的逗号，还原成数值
                pattern: /^(-)?[0-9]+([.][0-9]{1,})?$/g
            },
            "+money": {
                method: "regex",
                toOriginal: function (val) { return val.replace(/[,]/g, ""); }, //去掉格式化的逗号，还原成数值
                pattern: /^[0-9]+([.][0-9]{1,})?$/g
            },
            "digit": {
                method: "regex",
                pattern: /^[0-9]+$/g
            },
            "letter": {
                method: "regex",
                pattern: /^[a-zA-Z]+$/gi
            },
            "digitletter": {
                method: "regex",
                pattern: /^[a-zA-Z0-9]+$/gi
            },
            "date": {
                method: "regex",
                pattern: /^[0-9]{4}\-[0-9]{1,2}\-[0-9]{1,2}$/gi
            },
            "email": {
                method: "regex",
                pattern: /^[a-zA-Z0-9_\.\-]+\@([a-zA-Z0-9\-]+\.)+[a-zA-Z0-9]{2,4}$/
            },
            "mobile": {
                method: "regex",
                pattern: /^1\d{10}$/
            },
            "url": {
                method: "regex",
                pattern: /^(http|https|ftp):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)(:(\d+))?\/?/i
            },
            "range": {
                method: "range",
                toOriginal: function (val) { return val.replace(/[,]/g, ""); },
                message: function () {
                    var minVal = parseFloat(this.params[0]);
                    var maxVal = parseFloat(this.params[1]);
                    if (!isNaN(minVal) && !isNaN(maxVal)) {
                        return $.validation.format($.validation.messages["range1"], minVal, maxVal);
                    } else if (!isNaN(minVal)) {
                        return $.validation.format($.validation.messages["range2"], minVal);
                    } else {
                        return $.validation.format($.validation.messages["range3"], maxVal);
                    }
                }
            },
            "length": {
                method: "length",
                message: function () {
                    var minLen = parseInt(this.params[0], 10);
                    var maxLen = parseInt(this.params[1], 10);
                    if (isNaN(maxLen)) {
                        return $.validation.format($.validation.messages["length2"], minLen);
                    } else if (isNaN(minLen)) {
                        return $.validation.format($.validation.messages["length3"], maxLen);
                    } else {
                        return $.validation.format($.validation.messages["length1"], minLen, maxLen);
                    }
                }
            },
            "equalto": {
                method: "equalTo"
            },
            "func": {
                method: "func"
            }
        },
        // 验证函数集
        methods: {
            required: function (caller) {
                var val = getVal.call(this, caller);
                return !!$.trim(val);
            },
            regex: function (caller) {
                var val = getVal.call(this, caller);
                if (val && $.trim(val)) {
                    this.pattern.lastIndex = 0;
                    return this.pattern.test($.trim(val));
                } else
                    return true;
            },
            range: function (caller) {
                var val = getVal.call(this, caller);
                if (val && this.params) {
                    var fval = parseFloat(val);
                    var minVal = parseFloat(this.params[0]);
                    var maxVal = parseFloat(this.params[1]);
                    if ((!isNaN(minVal) && fval < minVal)
                        || (!isNaN(maxVal) && fval > maxVal)) {
                        return false;
                    }
                }

                return true;
            },
            length: function (caller) {
                var val = getVal.call(this, caller);
                if (val && this.params) {
                    var valLen = val.length;
                    var minLen = parseInt(this.params[0], 10) || 0;
                    var maxLen = parseInt(this.params[1], 10) || 9999999999;
                    return valLen >= minLen && valLen <= maxLen;
                } else {
                    return true;
                }
            },
            equalTo: function (caller) {
                if (this.params) {
                    var val = getVal.call(this, caller);
                    var toVal = $(this.params[0]).val();
                    return val == toVal;
                } else
                    return true;
            },
            func: function (caller) {
                var fn = getFunc(this.params[0]);
                if (typeof (fn) === "function") {
                    return fn.call(this, caller);
                } else {
                    return true;
                }
            }
        },
        //默认提示信息
        messages: {
            "required": "{name}不允许为空",
            "int": "{name}应该为整数",
            "+int": "{name}应该为正整数",
            "0+int": "{name}应该为0或正整数",
            "float": "{name}应该为数值",
            "+float": "{name}应该为正数",
            "money": "{name}应该为数值",
            "+money": "{name}应该为正数",
            "digit": "{name}应该为数字",
            "letter": "{name}应该为字母",
            "digitletter": "{name}应该为字母或数字",
            "date": "{name}应该为日期",
            "email": "{name}不是正确的邮箱地址",
            "mobile": "{name}不是正确的手机号码",
            "url": "{name}不是正确的网址",
            "range1": "{name}应该介于{0}和{1}之间",
            "range2": "{name}不能小于{0}",
            "range3": "{name}不能大于{0}",
            "length1": "{name}的长度应介于{0}和{1}之间",
            "length2": "{name}的长度不能小于{0}",
            "length3": "{name}的长度不能大于{0}",
            "equalto": "{name}输入不一致"
        },
        // 验证失败时元素的class
        errorClass: "error",
        /**
        * 验证失败处理函数,在验证失败是会调用，默认验证失败会弹出提示框，可重写该函数
        * this为当前验证失败的元素；
        * @params message (string) 表示验证失败提示信息
        */
        errorHandler: function (message) {
            $(this).attr("errormsg", message).addClass($.validation.errorClass).focus();
            alert(message); // 弹出异常提示框
        }
    };

    // 获取控件值
    function getVal(ele) {
        var value = $(ele).is("input, select, textarea") ? $(ele).val() : $(ele).text();
        if (typeof (this.toOriginal) === "function") {
            return this.toOriginal(value);
        } else {
            return value;
        }
    };

    //获取函数,函数不存在则返回null
    function getFunc(funcName) {
        var func = window;
        $.each(funcName.split("."), function () {
            func = func[this];
        });
        return typeof (func) === "function" ? func : null;
    }

    /**
	 * 验证
	 * @param all (bool) -可选参数，是否全部验证，默认为false
	 * @param validatorAttr (string) -可选参数，指定配置验证规则的属性，默认是validator
     * *要验证的控件必须是visible的控件(要有高宽度）
	 */
    $.fn.validate = function (all, validatorAttr) {
        //获取参数
        validatorAttr = typeof (all) === "string" ? all : ((typeof (validatorAttr) === "string" && validatorAttr) ? validatorAttr : "validator");
        all = typeof (all) === "boolean" ? all : false;

        var result = true;
        if ($(this).length == 1 && $(this).attr(validatorAttr)) {
            var validator = $(this).attr(validatorAttr);
            var validators = validator.split(" ");
            var message;
            for (var i = 0; i < validators.length; i++) {
                if (validators[i]) {
                    var ruleName = validators[i].match(/^[+-a-zA-Z]+/gi).toString().toLowerCase();
                    var rule = $.validation.rules[ruleName];
                    if (rule) {
                        var method = $.validation.methods[rule.method];
                        if (method) {
                            //获取参数
                            var parastr = validators[i].match(/\(\S+\)/gi);
                            if (parastr && (parastr = parastr[0])) {
                                rule.params = parastr.substring(1, parastr.length - 1).split(",");
                            }
                            result = result && method.call(rule, this); //调用验证函数(this是控件);
                            if (!result) {
                                //获取错误信息
                                if (rule.message) {
                                    if ($.isFunction(rule.message))
                                        message = rule.message.call(rule);
                                    else {
                                        message = rule.message;
                                    }
                                } else {
                                    message = $.validation.messages[ruleName];
                                }
                                break;
                            }
                        }
                    }
                }
            }
            var $theEle = $(this);
            //设置错误提示
            if (result) {
                $theEle.attr("errormsg", "").removeClass($.validation.errorClass);
            } else {
                var name = $theEle.attr("title")
                    || ($theEle.attr("id") && $("[for='" + $theEle.attr("id") + "']").text())
                    || ($theEle.attr("class") && $("[for='" + $theEle.attr("class") + "']").text());
                name = $.trim(name).replace(/[:：]/g, ''); // 去除名称后边的冒号
                message = message.replace("{name}", name);
                if (typeof ($.validation.errorHandler) === "function") {
                    $.validation.errorHandler.call(this, message);
                }
            }
            // else 当指定要验证的控件有多个时循环通用validate
        } else {
            var $validateEle = $(this), $validatorEleList;
            var validateEleFilter = "[" + validatorAttr + "]:visible"; //只验证可见的控件
            if ($validateEle.selector) {
                // 查找指定的元素或子元素中包含validator的元素
                $validatorEleList = $.unique($.merge($validateEle.find(validateEleFilter), $validateEle.filter(validateEleFilter)));
            } else {
                // 没有指定选择要验证控件则查找所有有validator的控件
                $validatorEleList = $(validateEleFilter);
            }
            // 历遍要验证的控件
            $.each($validatorEleList, function () {
                if (all || result) {
                    var valid = $(this).validate(all, validatorAttr);
                    result = result && valid;
                }
            });
        }

        return result;
    };

    //获取验证失败信息
    $.fn.getErrorMsg = function () {
        return $(this).attr("errormsg");
    };

    // 格式化字符串
    $.validation.format = function () {
        if (arguments.length == 0) {
            return "";
        } else {
            var source = arguments[0];
            if (typeof (source) === "string") {
                for (var i = 1; i < arguments.length; i++) {
                    source = source.replace(new RegExp("\\{" + (i - 1) + "\\}", "g"), arguments[i]);
                }
            }
            return source;
        }
    };
    //验证所有有validator的控件
    $.validate = function (all, validatorAttr) {
        return $().validate(all, validatorAttr);
    };

}(jQuery));

// 初始化
$(function () {

    // 初始化函数
    var initializers = {
        "required": requiredInit,
        "int": intInit,
        "+int": intInit,
        "float": floatInit,
        "+float": floatInit,
        "money": moneyInit,
        "+money": moneyInit,
        "length": lengthInit
    };

    // 必填验证控件初始化
    function requiredInit() {
        // 在必填项前边加*号span
        var eleId = $(this).attr("id");
        var eleClass = $(this).attr("class");
        var selector = eleId ? ("[for='" + eleId + "']") : "";
        selector += selector ? "," : "";
        selector += eleClass ? ("[for='" + eleClass + "']") : "";
        var $forEle = $(selector);
        if ($forEle.length > 0) {
            $forEle.before("<span class='must'>*</span>");
        }
    };

    // 整型控件初始化
    function intInit() {
        $(this).keyup(function (event) {
            if (isPermitKey(event)) {
                return;
            }
            var value = $(this).val();
            if (value) {
                var sign = value.charAt(0) == "-" ? "-" : "";
                value = value.replace(/[^\d]/g, "");
                $(this).val(sign + value);
            }
        });
    };

    // float控件初始化
    function floatInit() {
        $(this).keyup(floatInputLimit);
    };

    // money控件初始化
    function moneyInit() {
        // 货币型输入框在blur格式化为千分位
        $(this).keyup(floatInputLimit)
            .blur(function () {
                //格式化数值
                var value = $(this).val();
                if (value) {
                    $(this).val(toMoneyStr(value.replace(/[,]/g, "")));
                }
            })
            .focus(function () {
                var value = $(this).val();
                if (value) {
                    value = value.replace(/[,]/g, "");
                    $(this).val(value);
                }
            });
    };

    // 输入长度限制（仅对textarea有效）
    function lengthInit(validator) {
        if ($(this).is("textarea")) {
            var parastr = validator.match(/\(\S+\)/gi);
            if (parastr && (parastr = parastr[0])) {
                var params = parastr.substring(1, parastr.length - 1).split(",");
                if (parseInt(params[1], 10)) {
                    $(this).attr("maxLength", params[1])
                        .keydown(function (event) {
                            if (!(event.ctrlKey && event.keyCode == 86) // 非Ctrl+V
                                && isPermitKey(event)) {
                                return;
                            }
                            var maxLength = parseInt($(this).attr("maxLength"), 10);
                            var value = $(this).val();
                            if (value.length >= maxLength && !isSelectedText($(this)[0])) {
                                return false;
                            }
                        })
                        .blur(function () {
                            var maxLength = parseInt($(this).attr("maxLength"), 10);
                            var value = $(this).val();
                            if (value.length >= maxLength) {
                                $(this).val(value.substr(0, maxLength));
                            }
                        });
                }
            }
        }
    };

    // 字符串转成千分位格式字符串
    function toMoneyStr(str) {
        var money = parseFloat(str);
        var sign = money < 0 ? "-" : "";
        var fvalue = Math.abs(money).toFixed(2);
        var sMoney = fvalue.toString().replace(/^(\d+)((\.\d+)?)$/, function (s, s1, s2) {
            return s1.replace(/\d{1,3}(?=(\d{3})+$)/g, "$&,") + s2;
        });

        return sign + sMoney;
    };

    // 小数数值输入限制
    function floatInputLimit(event) {
        if (isPermitKey(event)) {
            return;
        }
        var value = $(this).val();
        if (value) {
            var sign = value.charAt(0) == "-" ? "-" : "";
            value = value.replace(/[^\d.]/g, "");
            //移除多余的小数点
            var pp = value.lastIndexOf(".");
            if (pp > -1) {
                value = value.substr(0, pp).replace(/[.]/g, "") + value.substr(pp);
            }
            $(this).val(sign + value);
        }
    };

    // 是否是允许的按键（限制键盘输入是允许按下的按键）
    function isPermitKey(event) {
        return (event.ctrlKey) || (
            event.keyCode == 8 /*backspace*/
                || event.keyCode == 9 /*Tab*/
                || event.keyCode == 27 /*Esc*/
                || (event.keyCode >= 33 && event.keyCode <= 40) /*PgUp PgDn End Home left up right down */
                || event.keyCode == 46 /*Delete*/
        );
    }

    // 是否选中文本(ele:文本控件)
    function isSelectedText(ele) {
        if (ele.selectionEnd != undefined) { //IE10后及chrome
            return ele.selectionEnd != ele.selectionStart;
        } else if (document.selection) {
            //IE10及之前版本
            return !!document.selection.createRange().text;
        }

        return false;
    }

    /*
    * 设置指定控件的限制
    */
    $.fn.setLimit = function (validatorAttr) {
        validatorAttr = validatorAttr || "validator";
        if ($(this).attr(validatorAttr)) {
            var validators = $(this).attr(validatorAttr).split(" ");
            for (var i = 0; i < validators.length; i++) {
                var validator = validators[i];
                if (validator) {
                    var ruleName = validators[i].match(/^[+-a-zA-Z]+/gi).toString().toLowerCase();
                    var initFn = initializers[ruleName];
                    if (typeof (initFn) === "function") {
                        initFn.call(this, validator);
                    }
                }
            }
        }
    };

    /*
    * 通过validator初始化控件
    * @param validatorAttr(string) 验配置证规则的属性，默认validator
    */
    function initByValidator(validatorAttr) {
        validatorAttr = validatorAttr || "validator";
        // 根据验证规则初始化控件
        $("[" + validatorAttr + "]").each(function () {
            $(this).setLimit(validatorAttr);
        });
    }

    initByValidator(); // 根据验证规则初始化控件
});